package main

import "fmt"

//////////////////////////////////////////////////////////////////////////////////////////////
//函数
func add(num1, num2 int) int { //返回一个值
	return num1 + num2
}

func addMultiSub(num1 int, num2 int) (int, int, int) { //返回多个值
	return num1 + num2, num1 - num2, num1 * num2
}

func sum(nums...int)int{ //变参
	total := 0
	for _, num := range nums{
		total += num
	}
	return total
}

func TestMain1(){
	num1,num2 := 22,11
	arr_num := []int{11,22,33}

	var C int = add(num1,num2)
	res1,res2,res3 := addMultiSub(num1,num2)
	var sum int = sum(arr_num...)  //注意此处的传参方式
	fmt.Println(C)
	fmt.Println(res1,res2,res3)
	fmt.Println(sum)
}



/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//值传递和引用传递：
//    cpp中可以值传递也可以引用传递（&）
//    python和java除了系统内建类型是值传递以外，都是引用传递
//    golang只有值传递，要改变值必须用指针参数






//////////////////////////////////////////////////////////////////////////////////////////////////////////
//方法
//Go 语言的方法其实是作用在接收者（receiver）上的一个函数，接收者是某种非内置类型的变量。因此方法是一种特殊类型的函数。
//接收者类型可以是（几乎）任何类型，不仅仅是结构体类型：任何类型都可以有方法，甚至可以是函数类型，可以是 int、bool、string 或数组的别名类型。但是接收者不能是一个接口类型。


//这个参数把这个方法绑定到这个参数对应的类型上。
//和函数关系
//方法是特殊的函数，定义在某一特定的类型上，通过类型的实例来进行调用，这个实例被叫接收者(receiver)。
//函数将变量作为参数：Function1(recv)
//方法在变量上被调用：recv.Method1()
//接收者必须有一个显式的名字，这个名字必须在方法中被使用。
//receiver_type 叫做 （接收者）基本类型，这个类型必须在和方法同样的包中被声明。

//在 Go 中，（接收者）类型关联的方法不写在类型结构里面，就像类那样；耦合更加宽松；类型和方法之间的关联由接收者来建立。
//方法没有和数据定义（结构体）混在一起：它们是正交的类型；表示（数据）和行为（方法）是独立的。

//注意： Go语言不允许为简单的内置类型添加方法，所以下面定义的方法是非法的。
func Add(a1,b2 int){ //函数合法
	fmt.Println(a1+b2)
}


//不能是内置数据类型
//func (a int)Add2(b int){ //方法非法
//	fmt.Println(a+b)
//}
//需要用Go语言的type，来临时定义一个和int具有同样功能的类型。这个类型不能看成是int类型的别名，它们属于不同的类型，不能直接相互赋值。

type myInt int
func Add2(a,b int){
	fmt.Println(a + b)
}

func (a myInt)Add2(b myInt)(myInt){
	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(a+b)

	return a + b
}

func TestMain3(){
	a,b := 3,4
	Add2(a,b)

	var num1,num2 myInt = 33,44
	fmt.Println(num1.Add2(num2))
	num2.Add2(num2)
	num1.Add2(num1)
    //num1.Add2 称作选择子（selector），它为接收者num1选择合适的Add2方法
}




//“类的”方法
//Go 语言不像其它面向对象语言一样可以写个类，然后在类里面写一堆方法，但其实Go语言的方法很巧妙的实现了这种效果：
// 我们只需要在普通函数前面加个接受者（receiver，写在函数名前面的括号里面），
// 这样编译器就知道这个函数（方法）属于哪个struct了。
type Obj struct {
	Name string
}

func (obj Obj)action(){ //接收者写在函数名前面的括号里
	fmt.Println("this is function")
}

func main(){
	//TestMain1()
	TestMain3()

	obj := Obj{}
	obj.action()
}
